package com.xinzhidi.web.netty.service;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinzhidi.common.constant.AgreementConstants;
import com.xinzhidi.common.utils.DateUtils;
import com.xinzhidi.common.utils.StringUtils;
import com.xinzhidi.common.utils.file.FileTypeUtils;
import com.xinzhidi.web.house.domain.Household;
import com.xinzhidi.web.house.service.IHouseholdService;
import com.xinzhidi.web.netty.entity.*;
import com.xinzhidi.web.netty.entity.dto.AgreementSeahorseValveListDto;
import com.xinzhidi.web.netty.mapper.AgreementSeahorseValveMapper;
import com.xinzhidi.web.netty.utils.NettyUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 海龙马调节阀协议-（实时数据）Service业务层处理
 *
 * @author cx
 * @date 2023-08-14
 */
@Service
@RequiredArgsConstructor
public class AgreementSeahorseValveService extends ServiceImpl<AgreementSeahorseValveMapper, AgreementSeahorseValve> {

    @Autowired
    private AgreementCommandService commandService;

    @Autowired
    private AgreementCommandFieldService commandFieldService;

    @Autowired
    private AgreementSeahorseValveHistoryService historyService;

    @Autowired
    private DeviceInstructionService deviceInstructionService;

    @Autowired
    private AgreementSeahorseValveMapper agreementSeahorseValveMapper;

    @Autowired
    private IHouseholdService householdService;

    @Autowired
    private AgreementHouseholdValveService agreementHouseholdValveService;

    @Autowired
    private AgreementHeatService agreementHeatService;

    /**
     * 海龙马调节阀协议-（实时数据）协议解析
     *
     * @param message           消息
     * @param deviceInstruction 指令
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> seahorseProtocolAnalysis(String message, DeviceInstruction deviceInstruction) {
        LambdaQueryWrapper<AgreementCommand> commandWrapper = new LambdaQueryWrapper<>();
        commandWrapper.eq(AgreementCommand::getType, AgreementConstants.InstructionType.RECEIVE)
                .eq(AgreementCommand::getProtocolType, deviceInstruction.getProtocolType())
                .eq(AgreementCommand::getInstructType, deviceInstruction.getInstructType());
        AgreementCommand command = commandService.getOne(commandWrapper);

        LambdaQueryWrapper<AgreementCommandField> commandFieldLambdaQueryWrapper = new LambdaQueryWrapper<>();
        commandFieldLambdaQueryWrapper.eq(AgreementCommandField::getCommandId, command.getId())
                .orderByAsc(AgreementCommandField::getSort);
        List<AgreementCommandField> commandFieldList = commandFieldService.list(commandFieldLambdaQueryWrapper);
        Map<String, Object> map = new HashMap<>();
        if (CollectionUtils.isEmpty(commandFieldList)) {
            return map;
        }

        for (AgreementCommandField commandField : commandFieldList) {
            Integer startNum = commandField.getStartNum();
            Integer endNum = commandField.getEndNum();
            String value = NettyUtils.getByteStr(startNum, endNum, message, commandField);
            FileTypeUtils.setValueByType(commandField.getFieldEnglish(), commandField.getFieldType(), map, value);
        }
        saveValve(message, map, command, deviceInstruction);
        //如果是业务标识为1的数据，表示没有平台上的业务，不做任何操作
        if (!deviceInstruction.getBusinessFlag().equals("1")) {
            //修改住户阀门实时数据
            Integer valveOpen = Integer.parseInt(map.get("valveOpen").toString());
            if(valveOpen >=0 && valveOpen <= 100){
                Household household = householdService.getById(deviceInstruction.getHouseholdId());
                household.setValveOpen(valveOpen);
                household.setValveReadTime(DateUtils.getNowDate());
                householdService.updateById(household);
            }
        }
        return map;
    }

    /**
     * 保存阀门数据
     *
     * @param map
     * @param deviceInstruction
     */
    private void saveValve(String message,
                           Map<String, Object> map,
                           AgreementCommand command,
                           DeviceInstruction deviceInstruction) {
        AgreementSeahorseValve seahorseValve;
        //判断户用阀门实时数据是否已存在，存在则更新，不存在则新增
        AgreementSeahorseValveListDto dto = new AgreementSeahorseValveListDto();
        dto.setDtuId(deviceInstruction.getDtuId());
        dto.setAddress(deviceInstruction.getAddress());
        dto.setInstructType(command.getInstructType());
        seahorseValve = this.getValve(dto);
        String dataFieldSerialNumber = this.getDataFieldSerialNumber(dto);
        if (seahorseValve != null) {
            seahorseValve.setInstructionSet(message);
            seahorseValve.setJsonData(JSON.toJSONString(map));
            seahorseValve.setUpdateTime(DateUtils.getNowDate());
        } else {
            seahorseValve = new AgreementSeahorseValve();
            seahorseValve.setDeviceInstructionId(deviceInstruction.getId());
            seahorseValve.setDtuId(deviceInstruction.getDtuId());
            seahorseValve.setProtocolName(command.getProtocolName());
            seahorseValve.setInstructType(command.getInstructType());
            seahorseValve.setInstructName(command.getInstructName());
            seahorseValve.setPlotId(deviceInstruction.getPlotId());
            seahorseValve.setBuildId(deviceInstruction.getBuildId());
            seahorseValve.setUnitId(deviceInstruction.getUnitId());
            seahorseValve.setHouseholdId(deviceInstruction.getHouseholdId());
            seahorseValve.setAddress(deviceInstruction.getAddress());
            seahorseValve.setDataFieldSerialNumber(dataFieldSerialNumber);
            seahorseValve.setInstructionSet(message);
            seahorseValve.setJsonData(JSON.toJSONString(map));
        }

        if (this.saveOrUpdate(seahorseValve)) {
            LambdaQueryWrapper<AgreementCommand> commandWrapper = new LambdaQueryWrapper<>();
            commandWrapper.eq(AgreementCommand::getType, AgreementConstants.InstructionType.RECEIVE)
                    .eq(AgreementCommand::getProtocolType, deviceInstruction.getProtocolType())
                    .eq(AgreementCommand::getInstructType, deviceInstruction.getInstructType());
            command = commandService.getOne(commandWrapper);
            //保存户用阀门协议-历史数据表（agreement_household_valve_history）
            AgreementSeahorseValveHistory valveHistory = new AgreementSeahorseValveHistory();
            valveHistory.setDeviceInstructionId(deviceInstruction.getId());
            valveHistory.setDtuId(deviceInstruction.getDtuId());
            valveHistory.setProtocolName(command.getProtocolName());
            valveHistory.setInstructType(command.getInstructType());
            valveHistory.setInstructName(command.getInstructName());
            valveHistory.setPlotId(deviceInstruction.getPlotId());
            valveHistory.setBuildId(deviceInstruction.getBuildId());
            valveHistory.setUnitId(deviceInstruction.getUnitId());
            valveHistory.setHouseholdId(deviceInstruction.getHouseholdId());
            valveHistory.setDeviceType(command.getDeviceType());
            valveHistory.setAddress(deviceInstruction.getAddress());
            valveHistory.setInstructionSet(message);
            valveHistory.setPrefix(command.getPrefix());
            valveHistory.setDeviceType(command.getDeviceType());
            valveHistory.setControlCode(command.getControlCode());
            valveHistory.setLengthField(command.getLengthField());
            valveHistory.setStartChar(command.getStartChar());
            valveHistory.setJsonData(JSON.toJSONString(map));
            valveHistory.setDataFieldInstruct(command.getDataFieldInstruct());
            valveHistory.setEndMark(command.getEndMark());
            historyService.save(valveHistory);
        }
        deviceInstruction.setStatus(AgreementConstants.InstructSendingState.RETURN_TO_NORMAL);
        deviceInstructionService.updateById(deviceInstruction);
    }

    /**
     * 获取序列号---dataFieldSerialNumber
     */
    public String getDataFieldSerialNumber(AgreementSeahorseValveListDto dto) {
        Integer number = 0;
        AgreementSeahorseValve unitValve = this.getAgreementValve(dto);
        if (unitValve == null) {
            return number.toString();
        }

        number = Integer.valueOf(unitValve.getDataFieldSerialNumber());
        if (number == 256) {
            number = 0;
        } else {
            number++;
        }

        return String.valueOf(number);
    }

    public AgreementSeahorseValve getAgreementValve(AgreementSeahorseValveListDto dto) {
        AgreementSeahorseValve valve = agreementSeahorseValveMapper.selectOne(buildGenTableQueryWrapper(dto));
        return valve;
    }

    private AgreementSeahorseValve getValve(AgreementSeahorseValveListDto dto) {
        AgreementSeahorseValve agreementHouseholdValve = agreementSeahorseValveMapper.selectOne(buildGenTableQueryWrapper(dto));
        return agreementHouseholdValve;
    }

    private LambdaQueryWrapper<AgreementSeahorseValve> buildGenTableQueryWrapper(AgreementSeahorseValveListDto dto) {
        LambdaQueryWrapper<AgreementSeahorseValve> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StringUtils.isNotBlank(dto.getProtocolName()), AgreementSeahorseValve::getProtocolName, dto.getProtocolName())
                .like(StringUtils.isNotBlank(dto.getInstructName()), AgreementSeahorseValve::getInstructName, dto.getInstructName())
                .eq(StringUtils.isNotBlank(dto.getInstructType()), AgreementSeahorseValve::getInstructType, dto.getInstructType())
                .eq(StringUtils.isNotNull(dto.getDtuId()), AgreementSeahorseValve::getDtuId, dto.getDtuId())
                .eq(StringUtils.isNotBlank(dto.getAddress()), AgreementSeahorseValve::getAddress, dto.getAddress());
        return wrapper;
    }


    /**
     * 海龙马调节阀-【读阀门地址】指令下发
     */
    public boolean readValveAddress(Long dtuId) {
        return agreementHouseholdValveService.readAddress(AgreementConstants.AgreementType.SEAHORSE_VALVE_METER, "2", dtuId);
    }

    /**
     * 海龙马调节阀-【写阀门地址】指令下发
     */
    public boolean writeAddress(Long dtuId, String oldAddress, String newAddress) {
        return agreementHouseholdValveService.saveAddressDeviceInstruction(AgreementConstants.AgreementType.SEAHORSE_VALVE_METER, "4", dtuId, oldAddress, newAddress);
    }

    /**
     * 海龙马调节阀-【写目标调节值】指令下发
     */
    public boolean writeByModel(Long dtuId, String address, String model, String value) {

        if (model.equals("00")) {
            value = "0000";
        }else{
            value = new BigDecimal(value).multiply(new BigDecimal(100)).toString();
            value = String.valueOf(Double.valueOf(value).intValue());
            Integer length = value.length();
            Integer maxLength = 4;
            Integer a = maxLength - length;
            if (a != 0) {
                for (int i = 0; i < a; i++) {
                    value = "0" + value;
                }
            }
//            value = HexadecimalUtil.convertToHighLow(value, 1);
        }
        return agreementHeatService.saveDeviceInstruction(AgreementConstants.AgreementType.SEAHORSE_VALVE_METER, dtuId, address, "3", model + value);
    }

    public DeviceInstruction getWriteByModel(Long dtuId, String address, String model, String value) {

        if (model.equals("00")) {
            value = "0000";
        }else{
            value = new BigDecimal(value).multiply(new BigDecimal(100)).toString();
            value = String.valueOf(Double.valueOf(value).intValue());
            Integer length = value.length();
            Integer maxLength = 4;
            Integer a = maxLength - length;
            if (a != 0) {
                for (int i = 0; i < a; i++) {
                    value = "0" + value;
                }
            }
//            value = HexadecimalUtil.convertToHighLow(value, 1);
        }
        return agreementHeatService.getDeviceInstruction(AgreementConstants.AgreementType.SEAHORSE_VALVE_METER, dtuId, address, "3", model + value);
    }


}
